package gatperdut.chato.core.interpreter;

import gatperdut.chato.constants.CSConstantsCommandResult.CommandExecutionResult;
import gatperdut.chato.core.characters.BaseController;
import gatperdut.chato.core.interpreter.actions.COIRAction;
import gatperdut.chato.core.interpreter.actions.CraftAction;
import gatperdut.chato.core.interpreter.actions.DirectionAction;
import gatperdut.chato.core.interpreter.actions.DocumentAction;
import gatperdut.chato.core.interpreter.actions.DropAction;
import gatperdut.chato.core.interpreter.actions.EmoteAction;
import gatperdut.chato.core.interpreter.actions.EmptyAction;
import gatperdut.chato.core.interpreter.actions.ExitsAction;
import gatperdut.chato.core.interpreter.actions.FillAction;
import gatperdut.chato.core.interpreter.actions.FleeAction;
import gatperdut.chato.core.interpreter.actions.FoodAction;
import gatperdut.chato.core.interpreter.actions.GetFromContainerAction;
import gatperdut.chato.core.interpreter.actions.GetFromRoomAction;
import gatperdut.chato.core.interpreter.actions.GiveAction;
import gatperdut.chato.core.interpreter.actions.HelpAction;
import gatperdut.chato.core.interpreter.actions.HitAction;
import gatperdut.chato.core.interpreter.actions.InvAction;
import gatperdut.chato.core.interpreter.actions.JunkAction;
import gatperdut.chato.core.interpreter.actions.ListItemTemplatesAction;
import gatperdut.chato.core.interpreter.actions.LookAroundAction;
import gatperdut.chato.core.interpreter.actions.LookAtAction;
import gatperdut.chato.core.interpreter.actions.LookInAction;
import gatperdut.chato.core.interpreter.actions.LookWornAction;
import gatperdut.chato.core.interpreter.actions.ManipulationContainerAction;
import gatperdut.chato.core.interpreter.actions.ManipulationDoorAction;
import gatperdut.chato.core.interpreter.actions.MudStatsAction;
import gatperdut.chato.core.interpreter.actions.PutAction;
import gatperdut.chato.core.interpreter.actions.QuitAction;
import gatperdut.chato.core.interpreter.actions.RemoveAction;
import gatperdut.chato.core.interpreter.actions.SayAction;
import gatperdut.chato.core.interpreter.actions.ScoreAction;
import gatperdut.chato.core.interpreter.actions.SetAction;
import gatperdut.chato.core.interpreter.actions.SetsAction;
import gatperdut.chato.core.interpreter.actions.ShoutAction;
import gatperdut.chato.core.interpreter.actions.ShutdownAction;
import gatperdut.chato.core.interpreter.actions.SkillsAction;
import gatperdut.chato.core.interpreter.actions.SpeakAction;
import gatperdut.chato.core.interpreter.actions.SpillAction;
import gatperdut.chato.core.interpreter.actions.StatusAction;
import gatperdut.chato.core.interpreter.actions.StopAction;
import gatperdut.chato.core.interpreter.actions.SwitchAction;
import gatperdut.chato.core.interpreter.actions.TellAction;
import gatperdut.chato.core.interpreter.actions.ThrowAction;
import gatperdut.chato.core.interpreter.actions.WearAction;
import gatperdut.chato.core.interpreter.actions.generic.Action;
import gatperdut.chato.core.interpreter.grammar.BailCommandLineGrammarLexer;
import gatperdut.chato.core.interpreter.grammar.comminfo.COIRInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.CommandInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.CommunicationInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.CraftInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.DocumentInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.EmoteInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.EmptyInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.ExitsInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.FillInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.FleeInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.FoodInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.GoInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.HelpInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.HitInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.InvInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.ItemTransferInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.JunkInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.ListItemTemplatesInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.LookInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.ManipulationContainerInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.ManipulationDoorInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.MudStatsInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.QuitInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.RemoveInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.ScoreInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.SetInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.SetsInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.ShutdownInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.SkillsInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.SpeakInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.SpillInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.StatusInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.StopInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.SwitchInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.ThrowInfo;
import gatperdut.chato.core.interpreter.grammar.comminfo.WearInfo;
import gatperdut.chato.core.interpreter.grammar.generated.CommandLineGrammarParser;
import gatperdut.chato.core.interpreter.grammar.generated.CommandLineGrammarParser.CommandContext;

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.BailErrorStrategy;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.TokenStream;

public abstract class BaseInterpreter {

    private final BaseController controller;

    public BaseInterpreter( BaseController controller ) {
        this.controller = controller;
    }

    public abstract boolean canCommand();

    public abstract boolean canEdit();

    public CommandExecutionResult exec( String command ) {

        CharStream charStream = new ANTLRInputStream( command );
        BailCommandLineGrammarLexer lexer = new BailCommandLineGrammarLexer( charStream );

        TokenStream tokenStream = new CommonTokenStream( lexer );
        CommandLineGrammarParser parser = new CommandLineGrammarParser( tokenStream );
        parser.setErrorHandler( new BailErrorStrategy() );

        CommandContext cc = null;
        try {
            cc = parser.command();
        }
        catch ( Exception mte ) {
            // mte.printStackTrace();
            getController().tx( "Check your syntax." );
            return CommandExecutionResult.OK;
        }

        CommandInfo ci = cc.commandInfo;

        if ( ci == null ) {
            getController().tx( "Huh? I don't recognize that command." );
            return CommandExecutionResult.OK;
        }
        Action action = createAction( ci );

        return action.perform();
    }

    private Action createAction( CommandInfo ci ) {
        Action a = null;

        switch ( ci.getCommandType() ) { // TODO: action class and info class as
                                         // fields of the enum literals.
        case DROP:
            a = new DropAction( (ItemTransferInfo) ci, getController() );
            break;
        case GIVE:
            a = new GiveAction( (ItemTransferInfo) ci, getController() );
            break;
        case QUIT:
            a = new QuitAction( (QuitInfo) ci, getController() );
            break;
        case GET_CONTAINER:
            a = new GetFromContainerAction( (ItemTransferInfo) ci, getController() );
            break;
        case GET_ROOM:
            a = new GetFromRoomAction( (ItemTransferInfo) ci, getController() );
            break;
        case GO:
            a = new DirectionAction( (GoInfo) ci, getController() );
            break;
        case MANIPULATION_CONTAINER:
            a = new ManipulationContainerAction( (ManipulationContainerInfo) ci, getController() );
            break;
        case MANIPULATION_DOOR:
            a = new ManipulationDoorAction( (ManipulationDoorInfo) ci, getController() );
            break;
        case HELP:
            a = new HelpAction( (HelpInfo) ci, getController() );
            break;
        case SETS:
            a = new SetsAction( (SetsInfo) ci, getController() );
            break;
        case INVENTORY:
            a = new InvAction( (InvInfo) ci, getController() );
            break;
        case LOOK:
            a = new LookAroundAction( (LookInfo) ci, getController() );
            break;
        case LOOK_AT:
            a = new LookAtAction( (LookInfo) ci, getController() );
            break;
        case LOOK_IN:
            a = new LookInAction( (LookInfo) ci, getController() );
            break;
        case LOOK_WORN:
            a = new LookWornAction( (LookInfo) ci, getController() );
            break;
        case FOOD:
            a = new FoodAction( (FoodInfo) ci, getController() );
            break;
        case DOCUMENT:
            a = new DocumentAction( (DocumentInfo) ci, getController() );
            break;
        case CRAFT:
            a = new CraftAction( (CraftInfo) ci, getController() );
            break;
        case EMOTE:
            a = new EmoteAction( (EmoteInfo) ci, getController() );
            break;
        case EXITS:
            a = new ExitsAction( (ExitsInfo) ci, getController() );
            break;
        case PUT:
            a = new PutAction( (ItemTransferInfo) ci, getController() );
            break;
        case HIT:
            a = new HitAction( (HitInfo) ci, getController() );
            break;
        case FLEE:
            a = new FleeAction( (FleeInfo) ci, getController() );
            break;
        case STOP:
            a = new StopAction( (StopInfo) ci, getController() );
            break;
        case SAY:
            a = new SayAction( (CommunicationInfo) ci, getController() );
            break;
        case LIST_ITEM_TEMPLATES:
            a = new ListItemTemplatesAction( (ListItemTemplatesInfo) ci, getController() );
            break;
        case SHOUT:
            a = new ShoutAction( (CommunicationInfo) ci, getController() );
            break;
        case TELL:
            a = new TellAction( (CommunicationInfo) ci, getController() );
            break;
        case THROW:
            a = new ThrowAction( (ThrowInfo) ci, getController() );
            break;
        case SPILL:
            a = new SpillAction( (SpillInfo) ci, getController() );
            break;
        case WEAR:
            a = new WearAction( (WearInfo) ci, getController() );
            break;
        case REMOVE:
            a = new RemoveAction( (RemoveInfo) ci, getController() );
            break;
        case STATUS:
            a = new StatusAction( (StatusInfo) ci, getController() );
            break;
        case SKILLS:
            a = new SkillsAction( (SkillsInfo) ci, getController() );
            break;
        case SET:
            a = new SetAction( (SetInfo) ci, getController() );
            break;
        case FILL:
            a = new FillAction( (FillInfo) ci, getController() );
            break;
        case SWITCH:
            a = new SwitchAction( (SwitchInfo) ci, getController() );
            break;
        case SCORE:
            a = new ScoreAction( (ScoreInfo) ci, getController() );
            break;
        case JUNK:
            a = new JunkAction( (JunkInfo) ci, getController() );
            break;
        case EMPTY:
            a = new EmptyAction( (EmptyInfo) ci, getController() );
            break;
        case SPEAK:
            a = new SpeakAction( (SpeakInfo) ci, getController() );
            break;
        case MUDSTATS:
            a = new MudStatsAction( (MudStatsInfo) ci, getController() );
            break;
        case COIR:
            a = new COIRAction( (COIRInfo) ci, getController() );
            break;
        case SHUTDOWN:
            a = new ShutdownAction( (ShutdownInfo) ci, getController() );
            break;
        default:
            throw new IllegalArgumentException( "Creating action with unsupported info." );
        }

        return a;
    }

    public BaseController getController() {
        return controller;
    }

}
